#include "mq_channel.hpp"

namespace mymq
{
    class Connection
    {
    public:
        using ptr = std::shared_ptr<Connection>;
        Connection(const VirtualHost::ptr& host,
            const ConsumerManager::ptr& cmp,
            const ProtobufCodecPtr& codec,
            const muduo::net::TcpConnectionPtr& conn,
            const ThreadPool::ptr& pool)
        : _conn(conn),
          _codec(codec),
          _cmp(cmp),
          _host(host),
          _pool(pool),
          _channels(std::make_shared<ChannelManager>())
        {}

        void openChannel(const openChannelRequestPtr& req)
        {
            // 检查信道是否重复
            bool ret = _channels->openChannel(req->cid(), _host, _cmp, _codec, _conn, _pool);
            if (ret == false)
            {
                DLOG("创建信道失败：信道 %s 重复", req->cid().c_str());
                return basicResponse(false, req->rid(), req->cid());
            }
            // 信道没有重复，创建成功
            DLOG("连接 %p 建立信道 %s 成功", _conn.get(), req->cid().c_str());
            return basicResponse(true, req->rid(), req->cid());
        }
        void closeChannel(const closeChannelRequestPtr& req)
        {
            _channels->closeChannel(req->cid());
            return basicResponse(false, req->rid(), req->cid());
        }
        Channel::ptr getChannel(const std::string cid)
        {
            return _channels->getChannel(cid);
        }

    private:
        // 发送通用的响应
        void basicResponse(bool ret, const std::string& rid, const std::string& cid)
        {
            basicCommonResponse resp;
            resp.set_rid(rid);
            resp.set_cid(cid);
            resp.set_ok(ret);
            _codec->send(_conn, resp);
        }
    private:
        // 构造信道需要什么句柄，这里都要
        muduo::net::TcpConnectionPtr _conn; // 底层使用的连接
        ProtobufCodecPtr _codec; // proto 协议处理
        ConsumerManager::ptr _cmp; // 消费者管理句柄
        VirtualHost::ptr _host; // 虚拟机句柄
        ThreadPool::ptr _pool; // 线程池
        ChannelManager::ptr _channels; // 信道管理句柄
    };

    class ConnectionManager
    {
    public:
        using ptr = std::shared_ptr<ConnectionManager>;
        ConnectionManager(){}
        void newConnection(const VirtualHost::ptr& host,
            const ConsumerManager::ptr& cmp,
            const ProtobufCodecPtr& codec,
            const muduo::net::TcpConnectionPtr& conn,
            const ThreadPool::ptr& pool)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 检测是否重复
            auto it = _conns.find(conn);
            if (it != _conns.end())
                return;
            
            // 连接不存在，构造新连接
            Connection::ptr newconn = std::make_shared<Connection>(host, cmp, codec, conn, pool);
            DLOG("新连接 %p 建立", conn.get());
            _conns.insert(std::make_pair(conn, newconn));
        }

        void delConnection(const muduo::net::TcpConnectionPtr& conn)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 检测是否存在
            auto it = _conns.find(conn);
            if (it == _conns.end())
                return;
            // 存在，删除
            _conns.erase(conn);
        }
        Connection::ptr getConnection(const muduo::net::TcpConnectionPtr& conn)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 检测是否存在
            auto it = _conns.find(conn);
            if (it == _conns.end())
                return Connection::ptr();
            return it->second;
        }
    private:
        std::mutex _mutex;
        // 映射关系：底层用于通信的 muduo 中的连接 --- 我们自己定义的管理信道的连接
        std::unordered_map<muduo::net::TcpConnectionPtr, Connection::ptr> _conns;
    };
}